package cn.wjssl.domain.strategy.service;

import cn.wjssl.domain.strategy.model.entity.StrategyAwardEntity;
import cn.wjssl.domain.strategy.model.valobj.RuleTreeVO;
import cn.wjssl.domain.strategy.model.valobj.RuleWeightVO;
import cn.wjssl.domain.strategy.model.valobj.StrategyAwardRuleModelVO;
import cn.wjssl.domain.strategy.model.valobj.StrategyAwardStockKeyVO;
import cn.wjssl.domain.strategy.repository.IStrategyRepository;
import cn.wjssl.domain.strategy.service.rule.chain.ILogicChain;
import cn.wjssl.domain.strategy.service.rule.chain.factory.DefaultChainFactory;
import cn.wjssl.domain.strategy.service.rule.tree.factory.DefaultTreeFactory;
import cn.wjssl.domain.strategy.service.rule.tree.factory.engine.IDecisionTreeEngine;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Map;


/**
 * 抽奖抽象类的子类, 主要是实现具体的过滤业务
 */
@Slf4j
@Component
public class DefaultRaffleStrategy extends AbstractRaffleStrategy implements IRaffleStock, IRaffleAward, IRaffleRule {

    @Resource
    private DefaultChainFactory chainFactory;

    @Resource
    private DefaultTreeFactory treeFactory;

    @Resource
    private IStrategyRepository repository;

    @Override
    public DefaultChainFactory.StrategyAwardVO raffleLogicChain(String userId, Long strategyId) {
        // 根据策略id, 获取对应的责任链
        ILogicChain logicChain = chainFactory.openLogicChain(strategyId);
        // 调用责任链过滤方法
        return logicChain.logicChain(userId, strategyId);
    }

    @Override
    public DefaultTreeFactory.StrategyAwardVO raffleLogicTree(String userId, Long strategyId, Integer awardId) {
        return raffleLogicTree(userId, strategyId, awardId, null);
    }

    @Override
    public DefaultTreeFactory.StrategyAwardVO raffleLogicTree(String userId, Long strategyId, Integer awardId, Date endDateTime) {
        // 根据awardId, 获取rule_model, 对应的就是treeId
        StrategyAwardRuleModelVO strategyAwardRuleModelVO = repository.queryStrategyAwardRuleModelVO(strategyId, awardId);
        // 如果是null, 那说明没有配置决策树, 直接返回抽奖结果即可
        if (strategyAwardRuleModelVO == null) {
            return DefaultTreeFactory.StrategyAwardVO.builder()
                    .awardId(awardId)
                    .build();
        }
        // 不然就该奖品的rule_model就是决策树Id
        String treeId = strategyAwardRuleModelVO.getRuleModels();
        // 根据treeId, 从redis获取决策树, 通过规则树, 获得对应的决策链装配
        RuleTreeVO ruleTreeVO = repository.queryRuleTreeVOByTreeId(treeId);
        // 如果没有规则树VO, 那就要抛出异常
        if (null == ruleTreeVO) {
            throw new RuntimeException("存在抽奖策略配置的规则模型 Key，未在库表 rule_tree、rule_tree_node、rule_tree_line 配置对应的规则树信息 " + strategyAwardRuleModelVO.getRuleModels());
        }
        IDecisionTreeEngine treeEngine = treeFactory.openLogicTree(ruleTreeVO);
        // 调用决策树过滤方法
        return treeEngine.logicTree(userId, strategyId, awardId, endDateTime);
    }

    @Override
    public StrategyAwardStockKeyVO takeQueueValue() throws InterruptedException {
        return repository.takeQueueValue();
    }

    @Override
    public void updateStrategyAwardStock(Long strategyId, Integer awardId) {
        repository.updateStrategyAwardStock(strategyId, awardId);
    }

    @Override
    public List<StrategyAwardEntity> queryStrategyAwardListByStrategyId(Long strategyId) {
        return repository.queryStrategyAwardList(strategyId);
    }

    @Override
    public List<StrategyAwardEntity> queryStrategyAwardListByActivityId(Long activityId) {
        Long strategyId = repository.queryStrategyIdByActivityId(activityId);
        return queryStrategyAwardListByStrategyId(strategyId);
    }

    @Override
    public Map<String, Integer> queryAwardRuleLockCount(String[] treeIds) {
        return repository.queryAwardRuleLockCount(treeIds);
    }

    @Override
    public List<RuleWeightVO> queryAwardRuleWeightByActivityId(Long activityId) {
        Long strategyId = repository.queryStrategyIdByActivityId(activityId);
        return queryAwardRuleWeightByStrategyId(strategyId);
    }

    @Override
    public List<RuleWeightVO> queryAwardRuleWeightByStrategyId(Long strategyId) {
        return repository.queryAwardRuleWeightByStrategyId(strategyId);
    }
}
